package com.shelpe.services.sinbad.controller.sinbad;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.time.DateUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.shelpe.services.sinbad.controller.EffectMetricDto;
import com.shelpe.services.sinbad.controller.dto.KeywordEffectDto;
import com.shelpe.services.sinbad.controller.dto.page.ListMybatisPage;
import com.shelpe.services.sinbad.dto.KeywordDto;
import com.shelpe.services.sinbad.entity.jpa.Adgroup;
import com.shelpe.services.sinbad.entity.jpa.DriveType;
import com.shelpe.services.sinbad.entity.jpa.MobileKeywordsDetail;
import com.shelpe.services.sinbad.entity.jpa.MobileKeywordsDetail.Status;
import com.shelpe.services.sinbad.model.Keyword;
import com.shelpe.services.sinbad.model.KeywordEffectExample;
import com.shelpe.services.sinbad.model.KeywordExample;
import com.shelpe.services.sinbad.model.RptKeyword;
import com.shelpe.services.sinbad.model.RptKeywordDto;
import com.shelpe.services.sinbad.model.RptKeywordParam;
import com.shelpe.services.sinbad.readdao.KeywordMapper;
import com.shelpe.services.sinbad.readdao.ReadRptKeywordMapper;
import com.shelpe.services.sinbad.repository.jpa.AdgroupRepository;
import com.shelpe.services.sinbad.repository.jpa.CampaignRepository;
import com.shelpe.services.sinbad.repository.jpa.MobileKeywordsRepository;
import com.shelpe.services.sinbad.service.RankingService;
import com.shelpe.services.sinbad.service.RptKeywordService;
import com.shelpe.services.sinbad.service.rpt.AdgroupService;
import com.shelpe.services.sinbad.service.simbaproxy.SyncClient;
import com.shelpe.services.sinbad.utils.DateUtil;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;

@RestController
@RequestMapping(value = "/sinbadservice/v2")
@Api("v2版关键词相关的API")
public class Keyword2Controller {
	@Autowired
	private RptKeywordService rptKeywordService;
	@Autowired
	private AdgroupRepository adgroupRepository;
	@Autowired
	private SyncClient syncClient;
	@Autowired
	private KeywordMapper keywordMapper;
	@Autowired
	private RankingService rankingService;
	@Autowired
	private ReadRptKeywordMapper rptKeywordMapper;
	@Autowired
	private MobileKeywordsRepository mobileKeywordRespository;
	@Autowired
	private AdgroupService adgroupService;
	@Autowired
	private CampaignRepository campaignRepository;

	@ApiOperation(value = "获取关键词列表")
	@RequestMapping(method = RequestMethod.GET, path = "/users/{user_id}/keywords")
	public ListMybatisPage<KeywordEffectDto> findAllAdgroup(@PathVariable("user_id") long userID,
			@RequestParam(name = "campaign_id", required = false, defaultValue = "0") long campaignID,
			@RequestParam(name = "adgroup_id", required = false, defaultValue = "0") long adgroupID,
			@RequestParam(name = "page_num", defaultValue = "1") int page,
			@RequestParam(name = "page_size", defaultValue = "15") int size,
			@RequestParam(name = "sort", defaultValue = "click") String sort,
			@RequestParam(name = "direct", defaultValue = "desc") String direct,
			@RequestParam(name = "days", required = false, defaultValue = "0") int days,
			@RequestParam(name = "start", required = false) String startDate,
			@RequestParam(name = "end", required = false) String endDate,
			@RequestParam(name = "device", required = false, defaultValue = "all") String device) {
		ListMybatisPage<KeywordEffectDto> dto = new ListMybatisPage<KeywordEffectDto>();
		dto.setContent(new ArrayList<KeywordEffectDto>());
		List<Long> adgroupIDs = this.alterByIDs(userID, campaignID, adgroupID);
		if (adgroupIDs == null || adgroupIDs.size() == 0) {
			return dto;
		}

		List<Adgroup> adgroups = this.adgroupRepository.findByAutoIDIn(adgroupIDs);
		if (adgroups == null || adgroups.size() == 0) {
			return dto;
		}
		Map<Long, Adgroup> adgroupMap = new HashMap<Long, Adgroup>();
		for (Adgroup adgroup : adgroups) {
			adgroupMap.put(adgroup.getAutoID(), adgroup);
		}

		int limitStart = (page - 1) * size;

		KeywordEffectExample rptExample = new KeywordEffectExample();
		rptExample.setUserId(userID);
		rptExample.setStart(limitStart);
		rptExample.setEnd(size);// 取得条数(size)
		rptExample.setOrderByClause(this.orderByClause(sort, direct));
		KeywordEffectExample.Criteria rptCriteria = this.buildRptKeywordExampleCriteria(rptExample, startDate, endDate,
				days, device);
		/**** 基于adgroupID(主键)进行查询 ***/
		rptCriteria.andAdgroupIdIn(adgroupIDs);
		List<RptKeywordDto> rptKeywords = this.rptKeywordMapper.selectByKeywordAndRpt(rptExample);
		if (rptKeywords == null || rptKeywords.size() == 0) {
			return dto;
		}
		for (RptKeywordDto rptKeyword : rptKeywords) {
			KeywordEffectDto effect = new KeywordEffectDto();
			Adgroup adgroup = adgroupMap.get(rptKeyword.getAdgroupId());
			effect.from(rptKeyword, adgroup);
			dto.getContent().add(effect);
		}
		/*** 获取总数 ****/
		KeywordExample ex = new KeywordExample();
		ex.setUserId(userID);
		KeywordExample.Criteria criteria = ex.createCriteria();
		criteria.andAdgroupIdIn(adgroupIDs);
		int count = this.keywordMapper.countByExample(ex);
		dto.from(page, size, count, dto.getContent().size());

		return dto;
	}

	@ApiOperation("获取关键词")
	@RequestMapping(method = RequestMethod.GET, path = "/adgroups/{adgroup_id}/@keywords")
	public List<KeywordDto> query(@PathVariable("adgroup_id") long adgroupID) {
		List<KeywordDto> dtos = new ArrayList<KeywordDto>();

		Adgroup adgroup = this.adgroupRepository.findOne(adgroupID);
		if (adgroup == null) {
			return dtos;
		}

		// 获取关键词元数据
		KeywordExample ex = new KeywordExample();
		ex.setUserId(adgroup.getUserID());
		KeywordExample.Criteria criteria = ex.createCriteria();
		criteria.andAdgroupIdEqualTo(adgroupID);
		List<Keyword> keywords = this.keywordMapper.selectByExample(ex);

		if (keywords != null && keywords.size() > 0) {
			for (Keyword kw : keywords) {
				KeywordDto dto = new KeywordDto();
				dto.from(kw, adgroup.getMobileDiscount());
				if (kw.getMatchscope() != null) {
					dto.setMatchscope(kw.getMatchscope());
				}
				if (kw.getIsDefaultPrice()) {
					dto.setIsDefaultPrice(1);
				}
				dto.from(adgroup);
				dtos.add(dto);
			}
		}
		return dtos;
	}

	@ApiOperation("获取关键词信息")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "device", defaultValue = "all", allowableValues = "pc, mobile, all", paramType = "query", dataType = "string") })
	@RequestMapping(method = RequestMethod.GET, path = "/adgroups/{adgroup_id}/keywords")
	public List<KeywordDto> findKeyword(@PathVariable("adgroup_id") long adgroupID,
			@RequestParam(name = "keyword_ids", required = false) List<Long> keywordIDs,
			@RequestParam(name = "days", required = false, defaultValue = "0") int days,
			@RequestParam(name = "device", required = false, defaultValue = "all") String device,
			@RequestParam(name = "start", required = false) String startDate,
			@RequestParam(name = "end", required = false) String endDate) {
		List<KeywordDto> dtos = new ArrayList<KeywordDto>();

		Adgroup adgroup = this.adgroupRepository.findOne(adgroupID);
		
		if (adgroup == null) {
			return dtos;
		}
		int budget = this.campaignRepository.findOne(adgroup.getCampaignID()).getBudget();
		/** 同步推广组下面的移动质量得分 */
		try {
			this.syncClient.synckeywordScore(adgroup.getUserID(), adgroupID);
		} catch (Exception e) {
			e.printStackTrace();
		}

		Map<Long, MobileKeywordsDetail> mapMobileKeywords = new HashMap<Long, MobileKeywordsDetail>();
		if (adgroup.getDriveType() == DriveType.mix) {
			List<MobileKeywordsDetail> mobileKeywords = this.mobileKeywordRespository
					.findByAdgroupIDAndStatus(adgroupID, Status.starting);
			if (mobileKeywords != null && mobileKeywords.size() > 0) {
				for (MobileKeywordsDetail mobileKeyword : mobileKeywords) {
					mapMobileKeywords.put(mobileKeyword.getKeywordID(), mobileKeyword);
				}
			}
		}

		// 获取关键词元数据
		KeywordExample ex = new KeywordExample();
		ex.setUserId(adgroup.getUserID());
		KeywordExample.Criteria criteria = ex.createCriteria();
		criteria.andAdgroupIdEqualTo(adgroupID);
		if (keywordIDs != null && keywordIDs.size() > 0) {
			criteria.andKeywordIdIn(keywordIDs);
		}
		List<Keyword> keywords = this.keywordMapper.selectByExample(ex);

		Map<Long, KeywordDto> dtoMap = new HashMap<Long, KeywordDto>();
		for (Keyword kw : keywords) {
			KeywordDto dto = new KeywordDto();
			dto.from(kw, adgroup.getMobileDiscount());
			if (kw.getMatchscope() != null) {
				dto.setMatchscope(kw.getMatchscope());
			}
			if (kw.getIsDefaultPrice()) {
				dto.setIsDefaultPrice(1);
			}
			dto.from(adgroup);
			dtoMap.put(kw.getKeywordId(), dto);
			dtos.add(dto);
		}

		// 获取关键词效果数据
		RptKeywordParam param = new RptKeywordParam();
		param.setUserId(adgroup.getUserID());
		param.setAdgroupId(adgroupID);
		if (keywordIDs != null && keywordIDs.size() > 0) {
			param.setKeywordIds(keywordIDs);
		}
		param.setupDevice(device);
		if (days > 0) {
			param.setupDays(days);
		}
		if (StringUtils.isNotBlank(startDate)) {
			param.setupDate(startDate, endDate);
		}
		if (StringUtils.isBlank(startDate) && days == 0) {
			days = 7;
			param.setupDays(days);
		}

		List<RptKeyword> rpts = rptKeywordService.getReportsTrend(param);
		// 获取移动端宝贝效果数据
		EffectMetricDto adgroupEffectMetirc = adgroupService.report(adgroupID, "mobile", 7, null, null);
		if (rpts != null && rpts.size() > 0) {
			for (RptKeyword rpt : rpts) {
				KeywordDto dto = dtoMap.get(rpt.getKeywordId());
				if (dto != null) {
					// 养分中的关键词
					if (adgroup.getDriveType().getValue() == 2) {
						MobileKeywordsDetail mobileKeyword = mapMobileKeywords.get(rpt.getKeywordId());
						if (mobileKeyword != null) {
							dto.setMobileMark(2);
							dto.setMobileAdgroupID(mobileKeyword.getMobileAdgroupID());
						}
					} else {						
						// 可养分
						if (budget >= 100 && dto.getMobileQscore() > 5 && dto.getMobileQscore() < 10 && rpt.getClick() > 10) {
							if (rpt.getRoi() > 0 || (rpt.getRoi() == 0 && (adgroupEffectMetirc.getFavTotal()
									+ adgroupEffectMetirc.getCartTotal()) > adgroupEffectMetirc.getCtr() * 0.05)) {
								dto.setMobileMark(1);
							}
						}
					}
					dto.from(rpt);
				}
			}
		} else {
		}

		// 关键词分类
		for (Keyword kw : keywords) {
			KeywordDto dto = dtoMap.get(kw.getKeywordId());
			if (dto != null) {
				this.setKeywordType(dto);
			}
		}
		// 查看关键词是否已在卡位
		this.rankingService.checkKeywordRanking(adgroup.getUserID(), dtos);
		
		//第二次过滤(过滤排名前三的) 根据无线排名 判断是否适合养分,淘宝接口每次只接受20个关键词所以两次过滤
		List<KeywordDto> mobileKeywords = new ArrayList<KeywordDto>();
		for(KeywordDto dto : dtos){
			if(dto.getMobileMark() == 1){
				mobileKeywords.add(dto);
			}
		}
		if(mobileKeywords.size()>0){
			mobileKeywords = adgroupService.filterMobileKeywordsByMobileRank(mobileKeywords, adgroup.getUserID());
			Map<Long,KeywordDto> mapDtos = new HashMap<Long,KeywordDto>();
			if(mobileKeywords!=null && mobileKeywords.size()>0){
				for(KeywordDto dto : mobileKeywords){
					mapDtos.put(dto.getKeywordID(), dto);
				}
			}
			for(KeywordDto dto : dtos){
				//标记为不适合养分
				if(mapDtos.get(dto.getKeywordID())==null && dto.getMobileMark()==1){
					dto.setMobileMark(0);
				}
			}
		}
		return dtos;
	}

	/********************************* 辅助方法 *****************************************************/
	private void setKeywordType(KeywordDto dto) {
		if (dto.getImpressions() == 0) {
			dto.setType("no_impressions");
		}
		if (dto.getImpressions() > 0 && dto.getClick() == 0) {
			dto.setType("impressions_no_click");
		}
		if (dto.getClick() > 0 && dto.getCvr() == 0.0f) {
			dto.setType("click_no_cvr");
		}
		if (dto.getCvr() > 0.0f) {
			dto.setType("cvr");
		}
	}

	private String orderByClause(String sort, String direct) {
		return sort + " " + direct;
	}

	private List<Long> alterByIDs(long userID, long campaignID, long adgroupID) {
		List<Long> adgorupIDs = new ArrayList<Long>();
		if (campaignID > 0) {
			List<Adgroup> adgroups = this.adgroupRepository.findByCampaignID(campaignID);
			if (adgroups != null && adgroups.size() > 0) {
				for (Adgroup adgroup : adgroups) {
					if (adgorupIDs.indexOf(adgroup.getAutoID()) == -1) {
						adgorupIDs.add(adgroup.getAutoID());
					}
				}
			}
		}
		if (adgroupID > 0) {
			Adgroup adgroup = this.adgroupRepository.findOne(adgroupID);
			if (adgroup != null) {
				adgorupIDs.add(adgroup.getAutoID());
			}
		}
		if (campaignID == 0 && adgroupID == 0) {
			List<Adgroup> adgroups = this.adgroupRepository.findByUserID(userID);
			if (adgroups != null && adgroups.size() > 0) {
				for (Adgroup adgroup : adgroups) {
					if (adgorupIDs.indexOf(adgroup.getAutoID()) == -1) {
						adgorupIDs.add(adgroup.getAutoID());
					}
				}
			}
		}
		return adgorupIDs;
	}

	private KeywordEffectExample.Criteria buildRptKeywordExampleCriteria(KeywordEffectExample example, String startDate,
			String endDate, int days, String device) {
		KeywordEffectExample.Criteria criteria = example.createCriteria();
		Date yesterday = DateUtils.addDays(DateUtils.truncate(new Date(), Calendar.DATE), -1);
		if (StringUtils.isBlank(startDate) && StringUtils.isBlank(endDate)) {
			startDate = DateFormatUtils.format(DateUtils.addDays(yesterday, -6), "yyyy-MM-dd");
			endDate = DateFormatUtils.format(yesterday, "yyyy-MM-dd");
		}
		if (days > 0) {
			startDate = DateFormatUtils.format(DateUtils.addDays(yesterday, -days + 1), "yyyy-MM-dd");
			endDate = DateFormatUtils.format(yesterday, "yyyy-MM-dd");
		}
		criteria.andDateBetween(DateUtil.parseDate2date(startDate), DateUtil.parseDate2date(endDate));
		if ("mobile".equals(device)) {
			criteria.andSourceBetween((byte) 4, (byte) 5);
		} else if ("pc".equals(device)) {
			criteria.andSourceBetween((byte) 1, (byte) 2);
		} else {
			criteria.andSourceBetween((byte) 1, (byte) 5);
		}
		return criteria;
	}
}
